﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using nGSO.Utils;
using System.Text.RegularExpressions;

namespace nGSO.Performance
{
    public class EffecinityCalc
    {
        private int _minAgentsAtPeak;
        private double _maxDistanceToPeak;
        private GsoConfig _config;
        private Dictionary<double[], List<double[]>> _groupedOptimums;

        public EffecinityCalc(GsoConfig config)
        {
            _config = config;

            var selectedCase = _config.SelectedOptimizationTask;
            string encodedOptima = selectedCase.EncodedOptima;
            OptimumCsvProvider csvOptimumProv = new OptimumCsvProvider();
            Dictionary<double[], List<double[]>> groupedOptimums = new Dictionary<double[], List<double[]>>();

            if (!String.IsNullOrWhiteSpace(encodedOptima))
            {

                Match fileName = Regex.Match(encodedOptima, "@file=(.+)@");

                if (fileName.Success)
                    csvOptimumProv.FillFromFile(groupedOptimums, fileName.Groups[1].Value);
                else
                    csvOptimumProv.FillFromString(groupedOptimums, encodedOptima);


                _groupedOptimums = groupedOptimums;
            }

            _minAgentsAtPeak = int.Parse(ConfigurationManager.AppSettings["PerfMinAgetnsAtPeak"]);
            _maxDistanceToPeak = double.Parse(ConfigurationManager.AppSettings["PerfMinAgentRangeFromPeak"]);
        }

        internal PeakAnalyzeData CountPeaks(IEnumerable<double[]> agentsLoc)
        {
            PeakAnalyzeData res = new PeakAnalyzeData();
            foreach (double[] loc in agentsLoc)
            {
                foreach (var realOptimum in _groupedOptimums.Keys)
                {
                    double distance = AgentExtensions.GetDistance(realOptimum, _config.Dims, loc);
                    if (distance < _maxDistanceToPeak)
                    {
                        _groupedOptimums[realOptimum].Add(loc);
                        continue; // TODO czy lokalziacja agenta moze byc w promieniu dozwolonym dwóch peaków?
                    }
                }
            }
            res.DetectedPeaks = _groupedOptimums.Where(s => s.Value.Count >= _minAgentsAtPeak).Count();
            res.TotalPeaks = _groupedOptimums.Count;

            foreach (var item in _groupedOptimums)
            {
                item.Value.Clear();
            }

            return res;
        }

    }
}
